#include "QQRTCVideoEngineByAgora.h"

agora::media::IVideoFrameObserver::VIDEO_FRAME_PROCESS_MODE QQRTCIVideoFrameObserver::getVideoFrameProcessMode()
{
	return VIDEO_FRAME_PROCESS_MODE::PROCESS_MODE_READ_WRITE;
}

agora::media::base::VIDEO_PIXEL_FORMAT QQRTCIVideoFrameObserver::getVideoFormatPreference()
{
	return agora::media::base::VIDEO_PIXEL_RGBA;
}

bool QQRTCIVideoFrameObserver::onCaptureVideoFrame(agora::rtc::VIDEO_SOURCE_TYPE sourceType, VideoFrame& videoFrame)
{
	return true;
}

bool QQRTCIVideoFrameObserver::onPreEncodeVideoFrame(agora::rtc::VIDEO_SOURCE_TYPE sourceType, VideoFrame& videoFrame)
{
	return false;
}

bool QQRTCIVideoFrameObserver::onMediaPlayerVideoFrame(VideoFrame& videoFrame, int mediaPlayerId)
{
	return false;
}

bool QQRTCIVideoFrameObserver::onRenderVideoFrame(const char* channelId, agora::rtc::uid_t remoteUid, VideoFrame& videoFrame)
{
	QImage image((uchar*)videoFrame.yBuffer, videoFrame.width, videoFrame.height, QImage::Format_RGBA8888);
	QPixmap pixmap = QPixmap::fromImage(image);
	emit updateVideoFrame(pixmap);
	return true;
}

bool QQRTCIVideoFrameObserver::onTranscodedVideoFrame(VideoFrame& videoFrame)
{
	return false;
}

QQRTCVideoEngineByAgora::QQRTCVideoEngineByAgora(QObject* parent)
	: QQRTCVideoEngine(parent)
{
	mRtcEngine = createAgoraRtcEngine();
	mEventHandler = new agora::rtc::IRtcEngineEventHandler;
	mVideoFrameObserver = new QQRTCIVideoFrameObserver;
	connect(mVideoFrameObserver, &QQRTCIVideoFrameObserver::updateVideoFrame, this, &QQRTCVideoEngine::updateVideoFrame);
}

QQRTCVideoEngineByAgora::~QQRTCVideoEngineByAgora()
{
	if (mInitialize) {
		mRtcEngine->muteLocalAudioStream(true);
		mRtcEngine->muteLocalVideoStream(true);
		mRtcEngine->muteAllRemoteAudioStreams(false);
		mRtcEngine->muteAllRemoteVideoStreams(false);
		mRtcEngine->stopPreview();
		mRtcEngine->leaveChannel();

		agora::rtc::VideoCanvas canvas;
		canvas.uid = 0;
		mRtcEngine->setupLocalVideo(canvas);

		mInitialize = false;
	}

	if (mRtcEngine) {
		mRtcEngine->release(true);
		mRtcEngine = nullptr;
	}

	if (mVideoFrameObserver) {
		delete mVideoFrameObserver;
		mVideoFrameObserver = nullptr;
	}

	if (mEventHandler) {
		delete mEventHandler;
		mEventHandler = nullptr;
	}

	if (mMediaEngine) {
		mMediaEngine.release();
	}
}

void QQRTCVideoEngineByAgora::startRealCommunicateVideo(const QVariantMap& info)
{
	agora::rtc::RtcEngineContext context;
	context.appId = APP_ID;
	context.eventHandler = mEventHandler;

	if (!mRtcEngine->initialize(context)) {
		mInitialize = true;
	}
	else {
		mInitialize = false;
	}

	mRtcEngine->enableAudio();
	mRtcEngine->enableVideo();
	mRtcEngine->enableLocalVideo(true);

	agora::rtc::ChannelMediaOptions option;
	option.channelProfile = agora::CHANNEL_PROFILE_COMMUNICATION;
	option.clientRoleType = agora::rtc::CLIENT_ROLE_BROADCASTER;
	option.publishMicrophoneTrack = true;
	option.publishCameraTrack = true;
	option.autoSubscribeAudio = true;
	option.autoSubscribeVideo = true;

	mMediaEngine.queryInterface(mRtcEngine, agora::rtc::INTERFACE_ID_TYPE::AGORA_IID_MEDIA_ENGINE);
	mMediaEngine->registerVideoFrameObserver(mVideoFrameObserver);

	// Potential memory leak
	mRtcEngine->joinChannel(
		APP_TOKEN,
		"123456",
		0,
		option);

	agora::rtc::VideoCanvas canvas;
	canvas.renderMode = agora::media::base::RENDER_MODE_TYPE::RENDER_MODE_HIDDEN;
	canvas.setupMode = agora::rtc::VIDEO_VIEW_SETUP_MODE::VIDEO_VIEW_SETUP_REPLACE;
	canvas.uid = 0;

	QWidget* local = info.value("local").value<QWidget*>();
	canvas.view = (void*)local->winId();
	mRtcEngine->setupLocalVideo(canvas);
	mRtcEngine->startPreview();
}

void QQRTCVideoEngineByAgora::stopRealCommunicateVideo(const QVariantMap& info)
{
	Q_UNUSED(info);

	if (mInitialize) {
		mRtcEngine->muteLocalAudioStream(true);
		mRtcEngine->muteLocalVideoStream(true);
		mRtcEngine->muteAllRemoteAudioStreams(false);
		mRtcEngine->muteAllRemoteVideoStreams(false);
		mRtcEngine->stopPreview();
		mRtcEngine->leaveChannel();

		agora::rtc::VideoCanvas canvas;
		canvas.uid = 0;
		mRtcEngine->setupLocalVideo(canvas);

		mInitialize = false;
	}
}